package org.zjx.core.client;

import org.zjx.core.GameAction;

import java.util.*;
import java.util.concurrent.*;

/**
 * 基于内存的动作拉取器实现（线程安全）
 *
 * 使用并发集合实现的动作拉取器，支持多线程环境下的安全操作。
 * 每个客户端有独立的动作队列和待确认动作集合。
 */
public class MemoryActionPuller implements ActionPuller {
    // 客户端ID到动作队列的映射，使用ConcurrentHashMap保证线程安全
    private final Map<String, BlockingQueue<GameAction>> clientQueues = new ConcurrentHashMap<>();

    // 客户端ID到待确认动作ID集合的映射，使用ConcurrentHashMap保证线程安全
    private final Map<String, Set<String>> pendingActions = new ConcurrentHashMap<>();

    /**
     * 拉取指定客户端的待执行动作（非阻塞）
     * @param clientId 客户端ID
     * @return 可选的游戏动作，如果没有待执行动作则返回空
     */
    @Override
    public Optional<GameAction> pullAction(String clientId) {
        // 获取或创建客户端的动作队列
        BlockingQueue<GameAction> queue = clientQueues.computeIfAbsent(
                clientId, k -> new LinkedBlockingQueue<>()
        );
        // 从队列中取出一个动作（非阻塞）
        return Optional.ofNullable(queue.poll());
    }

    /**
     * 注册新动作到指定客户端的队列
     * @param clientId 客户端ID
     * @param action 要注册的游戏动作
     */
    @Override
    public void registerAction(String clientId, GameAction action) {
        // 获取或创建客户端的动作队列
        clientQueues.computeIfAbsent(clientId, k -> new LinkedBlockingQueue<>())
                .add(action);
        // 将动作ID添加到待确认集合
        pendingActions.computeIfAbsent(clientId, k -> ConcurrentHashMap.newKeySet())
                .add(action.getActionId());
    }

    /**
     * 确认动作执行结果
     * @param clientId 客户端ID
     * @param actionId 动作ID
     * @param success 执行是否成功
     */
    @Override
    public void acknowledge(String clientId, String actionId, boolean success) {
        // 获取客户端的待确认动作集合
        Set<String> pending = pendingActions.get(clientId);
        if (pending != null) {
            // 从待确认集合中移除该动作ID
            pending.remove(actionId);
            // 失败处理逻辑
            if (!success) {
                // 1. 记录失败日志
                System.err.println("Action execution failed - Client: " + clientId + ", ActionID: " + actionId);

                // 2. 可以添加失败计数器（需要添加字段）
                // 由于不能修改类字段，这里只是概念性说明
                // 实际项目中可以添加:
                // failureCounters.computeIfAbsent(clientId, k -> new AtomicInteger()).incrementAndGet();
            }
        } else {
            // 客户端没有待确认动作记录，可能是重复确认或客户端不存在
            System.err.println("No pending actions found for client: " + clientId + ", ActionID: " + actionId);
        }
    }
}